package com.mjk.common.tools.encrypt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import javax.crypto.spec.SecretKeySpec;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT TOKEN生成
 * @author Administrator
 *
 */
public class JWTUtils {

	/**
	 * HMA256 key
	 */
	public static final String HMAC256_KEY = "secret";

	public static final String JWT_NAME = "token";
	private static final long ACCESS_TOKEN_EXPIRATION_MINUTES = 30;
	private static final long REFRESH_INTERVAL_MINUTES = 5;

	public static String generateAccessToken(String subject) {
		return generateToken(subject);
	}

	public static Claims parseToken(String token) {

		return Jwts.parser()
				.setSigningKey(getSecretKey())
				.parseClaimsJws(token)
				.getBody();
	}

	public static boolean isTokenExpired(Claims claims) {
		Date expiration = claims.getExpiration();
		Instant now = Instant.now();
		return expiration.toInstant().isBefore(now);
	}

	public static String refreshToken(String token) {
		Claims claims = parseToken(token);
		if (!isTokenExpired(claims)) {
			long remainingMinutes = calculateRemainingMinutes(claims.getExpiration());
			if (remainingMinutes <= REFRESH_INTERVAL_MINUTES) {
				// Token 快过期了，生成新的访问令牌
				String subject = claims.getSubject();
				return generateAccessToken(subject);
			}
		}
		return token;
	}

	private static String generateToken(String subject) {
		Instant now = Instant.now();
		Date issuedAt = Date.from(now);
		Date expiration = Date.from(now.plus(JWTUtils.ACCESS_TOKEN_EXPIRATION_MINUTES, ChronoUnit.MINUTES));

		Map<String, Object> header = new HashMap<>();
		header.put("alg", "HS256");
		header.put("typ", "JWT");

		Map<String, Object> claims = new HashMap<>();
		claims.put("sub", subject);

		return Jwts.builder()
				.setHeader(header)
				.setClaims(claims)
				.setIssuedAt(issuedAt)
				.setExpiration(expiration)
				.signWith(SignatureAlgorithm.HS512,getSecretKey())
				.compact();
	}


	private static SecretKeySpec getSecretKey() {
		return new SecretKeySpec(JWT_NAME.getBytes(), SignatureAlgorithm.HS512.getJcaName());
	}

	private static long calculateRemainingMinutes(Date expiration) {
		Instant now = Instant.now();
		Instant expirationInstant = expiration.toInstant();
		return ChronoUnit.MINUTES.between(now, expirationInstant);
	}

	/**
	 * 创建jwt 带超时时间
	 * @param params
	 * @param minutes
	 * @return
	 */
	public static String createTokenWithExpirs(Map<String,Object> params,int minutes) {
		try {
			Date now = new Date(System.currentTimeMillis());
			Map<String, Object> header = new HashMap<>();
			header.put("alg", "HS256");
			header.put("typ", "JWT");
            Map<String, Object> claims = new HashMap<>(params);
			LocalDateTime plus = LocalDateTime.now().plusMinutes(minutes);
			Date expiresAt = Date.from(plus.atZone(ZoneId.systemDefault()).toInstant());
			JwtBuilder jwtBuilder = Jwts.builder();
			return jwtBuilder
					.setHeader(header)  //header
					.setClaims(claims)  //payload 载荷
					.setSubject("user_token")
					.setIssuedAt(now)
					.setExpiration(expiresAt)
					.signWith(SignatureAlgorithm.HS256, HMAC256_KEY) //signature 签名信息
					.compact(); //拼接三部分字符串
		}catch(Exception e) {
			return null;
		}
	}
}
